class Snake {
   // 表示蛇头的元素
   head: HTMLElement
   // 蛇的身体(包括蛇头)
   bodies: HTMLCollection
   // 获取蛇的容器
   element: HTMLElement

   constructor() {
      this.element = document.querySelector('.snake')!
      this.head = document.querySelector('.snake > div')!
      this.bodies = this.element.getElementsByTagName('div')
   }

   // 获取蛇的坐标(蛇头坐标)
   get X() {
      return this.head.offsetLeft
   }
   get Y() {
      return this.head.offsetTop
   }
   // 设置蛇的坐标(蛇头坐标)
   set X(value) {
      // 如果新值和旧值相同，则不再修改
      if (this.X === value) {
         return
      }

      // 判断X是否在合法范围0-290
      if (value < 0 || value > 290) {
         // 说明蛇撞墙了，抛出一个异常
         throw new Error('蛇撞墙了')
      }

      // 修改x时，是在修改水平坐标，蛇在向左移动时，不能向右掉头，反之亦然
      if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
         // 如果发生了掉头，让蛇向反方向继续移动
         if (value > this.X) {
            // 则向右走
            value = this.X - 10
         } else {
            // 则向左走
            value = this.X + 10
         }
      }
      // 移动身体
      this.moveBody()
      this.head.style.left = value + 'px'
      // 检查是否撞到自己
      this.checkHeadBody()
   }
   set Y(value) {
      // 如果新值和旧值相同，则不再修改
      if (this.Y === value) {
         return
      }

      // 判断Y是否在合法范围0-290
      if (value < 0 || value > 290) {
         // 说明蛇撞墙了
         throw new Error('蛇撞墙了')
      }
      // 修改y时，是在修改垂直坐标，蛇在向下移动时，不能向上掉头，反之亦然
      if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
         // 如果发生了掉头，让蛇向反方向继续移动
         if (value > this.Y) {
            // 则向下走
            value = this.Y - 10
         } else {
            // 则向上走
            value = this.Y + 10
         }
      }

      // 移动身体
      this.moveBody()
      this.head.style.top = value + 'px'
      // 检查是否撞到自己
      this.checkHeadBody()
   }
   // 蛇增加身体的方法
   addBody() {
      // 向element中添加一个div
      const myDiv = document.createElement('div')
      this.element.insertAdjacentElement("beforeend", myDiv)
   }
   // 添加一个蛇身体移动的方法
   moveBody() {
      // 将后边的身体设置为前边身体的位置
      // 遍历获取所有的身体
      for (let i = this.bodies.length - 1; i > 0; i--) {
         // 获取前边身体的位置
         let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
         let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;
         // 将值设置到当前身体上
         (this.bodies[i] as HTMLElement).style.left = X + 'px';
         (this.bodies[i] as HTMLElement).style.top = Y + 'px';
      }
   }
   // 检查蛇头是否撞到身体的方法
   checkHeadBody() {
      // 获取所有的身体，检查其是否和蛇头的坐标发生重叠
      for (let i = 1; i < this.bodies.length; i++) {
         let bd = (this.bodies[i] as HTMLElement)
         if (this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
            // 进入判断说明蛇头撞到了身体，游戏结束
            throw new Error('撞到自己了~')
         }
      }
   }
}

export default Snake